import json
import time
import cv2
import requests
import numpy as np
import base64
from kafka import KafkaConsumer, KafkaClient
from kafka.structs import TopicPartition
import YITUYDN
import mongo_
import redis_
import faceToolsV2
import dnnDetect
import faceTools
import argparse
import ovo_f

parser = argparse.ArgumentParser()
parser.add_argument('-s')
parser.add_argument('-e')
args = parser.parse_args()
# print(args.o)
# print(args.v)


with open('../config.py', 'r') as f:
    exec(f.read())


def get_ovncam_dic(similarity, hitface_id, camera_id, new_similarity, is_front):
    hit_dic = {
        'similarity': similarity,
        'hit_face_image_id': hitface_id,
        'camera_id': camera_id,
        'ovo_similarity': new_similarity,
        'is_front': is_front
    }
    return hit_dic


def detect_front(detectFacev2, detectCount, detectFaceV1):
    if detectFaceV1['detectFace'] == 1:
        if detectFacev2 != 1 or detectCount >= 2 or abs(detectFaceV1['x']) > 40 or abs(
                detectFaceV1['y']) > 40 or abs(detectFaceV1['z']) > 40:
            return False
        else:
            return True
    else:
        return False


def get_image(img_dic):
    image_url = yituydn.getImgUrl(img_dic['face_image_uri'])
    try:
        file = requests.get(image_url)
    except Exception as e:
        raise Exception(str(e))
        return {}
    return file.content

def img_to_base64(bs):
    base64_data = base64.b64encode(bs)
    s = base64_data.decode()
    return s



def bsToCv(bs):
    image_ = cv2.imdecode(np.frombuffer(bs, np.uint8), 1)
    return image_


def insert_redis_mongo(images, data_dic):
    detectFacev2 = int(faceToolsV2.detect_(images))
    detectCount = dnnDetect.detect_(images)
    detectFaceV1 = faceTools.detect_(images)
    # print(detectFacev2)
    is_front = detect_front(detectFacev2, detectCount, detectFaceV1)
    # 入db15
    db15_data = {
        'camera_id': data_dic['camera_id'],
        'face_image_id': data_dic['face_image_id'],
        'face_image_uri': data_dic['face_image_uri'],
        'picture_uri': data_dic['picture_uri'],
        'timestamp': data_dic['timestamp'],
        '_id': data_dic['face_image_id'],
        'ip': H_IP,
        'detectFacev2': detectFacev2,
        'detectCount': detectCount,
        'yitu_171_feature_base64': data_dic['yitu_171_feature_base64'],
        'is_front': is_front,
        'f': data_dic['f']
    }
    db15_data.update(detectFaceV1)
    # 入redis
    for key in db15_data:
        redis_.insert(data_dic['face_image_id'], key, str(db15_data[key]))
    # 入mongo
    mongo_.insert_cap(db15_data)
    return is_front

# skip_count = 430003

yituydn = YITUYDN.YITUYDN(yituinfo['ip'], yituinfo['port'], yituinfo['username'],
                          yituinfo['password'])

H_IP = yituydn.ip
cluster_id = yituydn.getCluster_id()
camera_list = yituydn.camera_list(yituydn.getcamera())
repository_list = yituydn.repository_list(yituydn.getrepository())

time_interval = 10
now_time = int(time.time())


skip_time = now_time - 3600 * 5 * 24

time_img = mongo_.get_time()
if time_img:
    skip_time = max(skip_time, time_img['update_time'])


while True:
    try:
        if args.s:
            stop = True
            all_data_mongo = mongo_.repo_man_.find({"camera_id": {'$exists': True}, 'timestamp': {'$gt': int(args.s), '$lt': int(args.e)}}).limit(200000)
        else:
            stop = False
            all_data_mongo = mongo_.repo_man_.find({"camera_id": {'$exists': True}, 'timestamp': {'$gt': skip_time}}).limit(100000)

        all_data_list = []
        for message in all_data_mongo:
            all_data_list.append(message)

        for message in all_data_list:
            try:
                if not args.s:
                    skip_time = max(skip_time, message['timestamp'])
                    mongo_.update_time(skip_time)
                    print(skip_time)

                data = message
                print('run1 runing', time.time())

                if int(time.time()) - now_time >= time_interval:
                    now_time = int(time.time())
                    camera_list = yituydn.camera_list(yituydn.getcamera())
                    repository_list = yituydn.repository_list(yituydn.getrepository())
                # print(data)

                data['camera_id'] = str(data['camera_id']) + '@' + cluster_id
                data['face_image_id'] = str(int(data['_id'].__str__(), 16)) + '@' + cluster_id
                data['face_image_uri'] = str(data['face_image_uri']) + '@' + cluster_id
                data['picture_uri'] = str(data['picture_uri']) + '@' + cluster_id

                # face_yitu_171_feature_base64 = data['yitu_171_feature_base64']
                face_img_id = data['face_image_id']
                bs = get_image(data)
                # print(bs)
                if len(bs) < 2000:
                    continue
                # if bs['rtn']
                # f_base64 = ovo_f.get_f(img_to_base64(bs))
                # data['f'] = f_base64
                image = bsToCv(bs)
                if image is None:
                    continue
                face_has_rdb = redis_.haskey(face_img_id)
                if face_has_rdb:
                    f_base64 = redis_.RDB_getFace(face_img_id)['f']
                    data['f'] = f_base64


                if not face_has_rdb:
                    f_base64 = ovo_f.get_f(img_to_base64(bs))
                    data['f'] = f_base64
                    # 插入数据
                    insert_redis_mongo(image, data)

                # db15取出is_front
                face_front = redis_.RDB_getFace(face_img_id)['is_front']

                image_content_base64 = base64.b64encode(bs).decode()
                cam_ovn = yituydn.ovn(camera_list, None, image_content_base64, guidanginfo['face_similarity'], [], [],
                                      guidanginfo['face_limit'])
                card_ovn = yituydn.ovn(None, repository_list, image_content_base64, guidanginfo['card_similarity'], [], [],
                                       guidanginfo['card_limit'])
                ebn_result = []
                if cam_ovn['rtn'] == 0:
                    # 第一遍循环统计数据
                    hit_face_acvs_dic = {}
                    face_front_dic = {}
                    acvs_list = []
                    for img_hit in cam_ovn['results']:
                        hit_face_id = img_hit['face_image_id']
                        if hit_face_id == face_img_id:
                            continue
                        hit_face_has = redis_.haskey(hit_face_id)
                        # print('hit_face_has', hit_face_has)
                        bs1 = get_image(img_hit)
                        if len(bs1) < 2000:
                            continue
                        hit_image = bsToCv(bs1)
                        if hit_image is None:
                            continue
                        if not hit_face_has:
                            img_base64 = ovo_f.get_f(img_to_base64(bs1))
                            img_hit['f'] = img_base64
                            insert_redis_mongo(hit_image, img_hit)
                        if face_front:
                            hit_face_front = redis_.RDB_getFace(hit_face_id)['is_front']
                            face_front_dic[hit_face_id] = hit_face_front
                            if hit_face_front:
                                hit_face_acvs_dic[hit_face_id] = []
                                redis_.RDB_getfaceacvsall(hit_face_id, hit_face_acvs_dic, acvs_list, start=0, end=-1)
                    # 统计
                    if not face_front:
                        for img_hit in cam_ovn['results']:
                            similarity = img_hit['similarity']
                            camera_id = img_hit['camera_id']
                            hitface_id = img_hit['face_image_id']
                            if hitface_id == face_img_id:
                                continue
                            hitface_front = redis_.RDB_getFace(hitface_id)['is_front']
                            hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, 0, hitface_front)
                            ebn_result.append(hit_dic)

                    if face_front:
                        # 第二遍插入数据
                        for img_hit in cam_ovn['results']:
                            acvs_tuple_list = []
                            count_list = []
                            similarity = img_hit['similarity']
                            camera_id = img_hit['camera_id']
                            hitface_id = img_hit['face_image_id']
                            if hitface_id == face_img_id:
                                continue
                            # 97 98侧脸
                            if hitface_id not in hit_face_acvs_dic:
                                hitface_front = False
                                hit_dic = {
                                    'similarity': similarity,
                                    'hit_face_image_id': hitface_id,
                                    'camera_id': camera_id,
                                    'is_front': False
                                }
                                ebn_result.append(hit_dic)

                            else:
                                hit_acvs_list = hit_face_acvs_dic[img_hit['face_image_id']]
                                # 正脸没有档
                                if len(hit_acvs_list) == 0:

                                    # ovo获取base64之前判断 db15 是否含有这个face_id

                                    hit_f_base64 = redis_.RDB_getFace(img_hit['face_image_id'])['f']
                                    # hit_f_base64 = ovo_f.get_f(img_to_base64(get_image(img_hit)))


                                    # hit_image_yitu_171_feature_base64 = img_hit['yitu_171_feature_base64']
                                    # ovo_rtn = yituydn.ovo(face_yitu_171_feature_base64, hit_image_yitu_171_feature_base64)
                                    # if ovo_rtn['rtn'] == 0:
                                    #     new_similarity = ovo_rtn['similarity']
                                    # else:
                                    #     new_similarity = -1
                                    new_similarity = ovo_f.get_ovo_sim(f_base64, hit_f_base64)
                                    hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, new_similarity,
                                                             face_front_dic[hitface_id])
                                    hit_dic['acvs_id'] = acvs_tuple_list
                                    ebn_result.append(hit_dic)
                                # 正脸有档
                                else:
                                    for acvs_id in hit_acvs_list:
                                        acvs_tuple_list.append((acvs_id, acvs_list.count(acvs_id)))
                                        count_list.append(acvs_list.count(acvs_id))
                                    count_max = max(count_list)
                                    if count_max < 2:
                                        hit_f_base64 = redis_.RDB_getFace(img_hit['face_image_id'])['f']
                                        # hit_f_base64 = ovo_f.get_f(img_to_base64(get_image(img_hit)))


                                        # hit_image_yitu_171_feature_base64 = img_hit['yitu_171_feature_base64']
                                        # ovo_rtn = yituydn.ovo(face_yitu_171_feature_base64,
                                        #                       hit_image_yitu_171_feature_base64)
                                        # if ovo_rtn['rtn'] == 0:
                                        #     new_similarity = ovo_rtn['similarity']
                                        # else:
                                        #     new_similarity = -1
                                        new_similarity = ovo_f.get_ovo_sim(f_base64, hit_f_base64)
                                        hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, new_similarity,
                                                                 face_front_dic[hitface_id])
                                        hit_dic['acvs_id'] = acvs_tuple_list
                                        ebn_result.append(hit_dic)
                                    else:
                                        hit_dic = get_ovncam_dic(similarity, hitface_id, camera_id, count_max * 100,
                                                                 face_front_dic[hitface_id])
                                        hit_dic['acvs_id'] = acvs_tuple_list
                                        ebn_result.append(hit_dic)

                else:
                    camera_list = yituydn.camera_list(yituydn.getcamera())
                    repository_list = yituydn.repository_list(yituydn.getrepository())
                    continue

                if card_ovn['rtn'] == 0:
                    for card_hit_img in card_ovn['results']:
                        hit_card_id = card_hit_img['face_image_id']
                        hit_card_has = redis_.haskey(hit_card_id)

                        bs2 = get_image(card_hit_img)
                        if len(bs2) < 2000:
                            continue
                        hitcard_image = bsToCv(bs2)

                        if hitcard_image is None:
                            continue

                        if hit_card_has != 1:
                            card_base64 = ovo_f.get_f(img_to_base64(bs2))

                            data15_card = {
                                'repository_id': card_hit_img['repository_id'],
                                'face_image_id': card_hit_img['face_image_id'],
                                'face_image_uri': card_hit_img['face_image_uri'],
                                'picture_uri': card_hit_img['picture_uri'],
                                'timestamp': card_hit_img['timestamp'],
                                '_id': card_hit_img['face_image_id'],
                                'ip': H_IP,
                                'name': card_hit_img['name'],
                                'person_id': card_hit_img['person_id'],
                                'yitu_171_feature_base64': card_hit_img['yitu_171_feature_base64'],
                                'f': card_base64
                            }
                            # 入redis
                            for card_key in data15_card:
                                redis_.insert(hit_card_id, card_key, data15_card[card_key])
                            # 入mongo
                            mongo_.insert_cap(data15_card)

                        similarity = card_hit_img['similarity']
                        repository_id = card_hit_img['repository_id']
                        card_hit_dic = {
                            'similarity': similarity,
                            'hit_face_image_id': hit_card_id,
                            'hit_repository_id': repository_id
                        }
                        ebn_result.append(card_hit_dic)
                else:
                    camera_list = yituydn.camera_list(yituydn.getcamera())
                    repository_list = yituydn.repository_list(yituydn.getrepository())
                    continue

                ebn_result = sorted(ebn_result, key=lambda x: x['similarity'], reverse=True)
                ebndata = {
                    "face_image_id": face_img_id,
                    "result": ebn_result,
                    "is_front": face_front,
                    "timestamp": data['timestamp']
                }
                # 插入ebn结果
                redis_.insertebn(json.dumps(ebndata))

            except Exception as e:
                print(e)
                time.sleep(5)
                continue
        if stop:
            break
    except Exception as e:
        print(e)
        time.sleep(5)
